package study.activiti.b_processDefinition;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.io.FileUtils;
import org.junit.Test;

/**  
 * @Name: ProcessDefinitionTest
 * @Description: 流程定义测试类：流程定义的CRUD操作
 * @Author: 李超
 * @Create Date: 2016-12-11
 */
public class ProcessDefinitionTest {
	
	//获取流程引擎对象
	ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine() ;
	
	/**  
	* @Name: deploymentProcessDefinition_classpath（方法的名称）
	* @Description: 部署流程定义文件（classpath路径加载流程定义文件）（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void deploymentProcessDefinition_classpath() {
		//部署流程定义文件，返回部署对象
		Deployment deployment = processEngine.getRepositoryService() //获取仓库对象
					 .createDeployment() //产生部署配置对象，用来封装部署操作的相关配置
					 .name("部署流程的名称") //在部署配置对象中设置显示名
					 .addClasspathResource("diagrams/Helloworld.bpmn") //上传流程定义规则文件
					 .addClasspathResource("diagrams/Helloworld.png") 
					 .deploy() ;
		System.out.println("id[部署id]：" + deployment.getId()); //17501，对应act_re_deployment表中的ID_字段值
		System.out.println("name[部署名称]：" + deployment.getName()); //部署流程的名称，对应act_re_deployment表中的NAME_字段值
	}
	
	/**  
	* @Name: delpoymentProcessDefinition_zip（方法的名称）
	* @Description: 部署流程定义文件（zip格式文件）（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void delpoymentProcessDefinition_zip() {
		//获取上传文件的输入流对象
		InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/HelloWorld.zip") ;
		ZipInputStream zipInputStream = new ZipInputStream(in) ;
		//获取仓库服务，从类路径下完成部署
		Deployment deployment = processEngine.getRepositoryService() //获取仓库服务
					 .createDeployment() //创建部署对象
					 .name("部署流程的名称")  //添加部署的名称
					 .addZipInputStream(zipInputStream) //使用zip的输入流完成部署
					 .deploy() ; //完成部署->发布流程
		System.out.println("id[部署id]：" + deployment.getId()); 
		System.out.println("name[部署名称]：" + deployment.getName()); 
	}
	
	/**  
	* @Name: delpoymentProcessDefinition_inputStream（方法的名称）
	* @Description: 部署流程定义文件（输入流加载资源文件）（方法的描述）
	* 输入流加载资源文件的三种方式
	* 		1、从classpath跟目录下加载指定名称的文件
	* 		  InputStream in = this.getClass().getClassLoader().getResourceAsStream("test.bpmn") ;
	* 		2、从当前包下加载指定名称的文件
	* 		  InputStream in = this.getClass().getResourceAsStream("test.bpmn") ;
	* 		3、从classpath跟目录下加载指定名称的文件
	* 		  this.getClass().getResourceAsStream("/test.bpmn") ;
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void delpoymentProcessDefinition_inputStream() {
		InputStream inputStreamBpmn = this.getClass().getResourceAsStream("/diagrams/HelloWorld.bpmn") ;
		InputStream inputStreamPng = this.getClass().getResourceAsStream("/diagrams/HelloWorld.png") ;
		Deployment deployment = processEngine.getRepositoryService()
					 .createDeployment()
					 .name("部署流程的名称")
					 .addInputStream("HelloWorld.bpmn", inputStreamBpmn) //指定资源名称
					 .addInputStream("HelloWorld.png", inputStreamPng) //指定资源名称
					 .deploy() ; //发布流程
		System.out.println("id[部署id]：" + deployment.getId()); 
		System.out.println("name[部署名称]：" + deployment.getName()); 
	}
	
	/**  
	* @Name: findProcessDefinition（方法的名称）
	* @Description: 查询已部署流程定义的信息（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void findProcessDefinition() {
		List<ProcessDefinition> list = processEngine.getRepositoryService() //获取仓库服务：与流程定义和部署对象相关的Service
					 .createProcessDefinitionQuery() //创建一个流程定义的查询，查询表act_re_procdef中的信息
					 //1、设置查询条件，where部分
//					 .deploymentId(deploymentId) //使用部署对象ID查询
//					 .processDefinitionId(processDefinitionId) //使用流程定义ID查询
//					 .processDefinitionKey(processDefinitionKey) //使用流程定义的key查询
//					 .processDefinitionNameLike(processDefinitionNameLike) //使用流程定义的名称模糊查询
					 //2、排序
					 .orderByProcessDefinitionVersion().asc() //按照版本的升级排序
//					 .orderByProcessDefinitionName().desc() //按照流程定义的名称降序排序
					 //3、返回结果集
					 .list() ; //返回集合列表，封装流程定义
//					 .singleResult() ; //返回唯一的结果集
//					 .count() ; //返回结果集数量
//					 .listPage(firstResult, maxResult) ; //分页查询
		//4、遍历集合，查看查询结果
		if(list != null && list.size() > 0) {
			for (ProcessDefinition pd : list) {
				System.out.println("流程定义ID:" + pd.getDeploymentId()); //流程定义的key+版本+随机生成数
				System.out.println("流程定义名称:" + pd.getName()); //对应helloworld.bpmn文件中的name属性值
				System.out.println("流程定义的key:" + pd.getKey()); //对应helloworld.bpmn文件中的id属性值
				System.out.println("流程定义的版本号:" + pd.getVersion()); //当key相同时，版本升级，默认为1
				System.out.println("资源名称bpmn文件:" + pd.getResourceName());
				System.out.println("资源名称png文件:" + pd.getDiagramResourceName());
				System.out.println("部署对象ID:" + pd.getDeploymentId());
				System.out.println("######################################");
			}
		}
	}
	
	/**  
	* @Name: deleteProcessDefinitionByDeloymentID（方法的名称）
	* @Description: 根据部署ID删除已部署的流程定义（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void deleteProcessDefinitionByDeloymentID() {
		//使用部署ID，完成删除
		String deploymentId = "20001" ;
		processEngine.getRepositoryService() //获取仓库服务：与流程定义和部署对象相关的Service
//					 .deleteDeployment(deploymentId) ; //删除流程定义，此为不带级联的删除，只能删除没有启动的流程，如果启动流程，就会抛出异常
					 .deleteDeployment(deploymentId, true) ; //删除流程定义，级联删除，不管流程是否启动，都可以删除
		System.out.println("删除成功！");
	}
	
	/**  
	* @Name: viewImage（方法的名称）
	* @Description: 获取流程定义文档的资源（查看流程图附件），对应资源文件表：act_ge_bytearray（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	* @throws IOException 
	*/
	@Test
	public void viewImage() throws IOException {
		//指定部署id
		String deloymentId = "20001" ;
		//获取图片资源名称
		List<String> list = processEngine.getRepositoryService()
					 .getDeploymentResourceNames(deloymentId) ; //根据部署id获取流程资源名称
		String resourceName = "" ;
		if(list != null && list.size() > 0) {
			for (String name : list) {
				if(name.indexOf(".png") >= 0) {
					resourceName = name ;
				}
			}
		}
		//获取图片的输入流
		InputStream in = processEngine.getRepositoryService()
					 .getResourceAsStream(deloymentId, resourceName) ; //根据部署id和流程资源名称获取图片资源的输入流对象
		//将输入流的图片写到D盘
		File file = new File("D:/" + resourceName) ;
		FileUtils.copyInputStreamToFile(in, file) ;
	}
	
	/**  
	* @Name: findLastVersionProcessDefinition（方法的名称）
	* @Description: 附加功能：查询最新版本的流程定义（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void findLastVersionProcessDefinition() {
		//1、查询所有的流程定义，升序排列，把最新的版本放到后边
		List<ProcessDefinition> list = processEngine.getRepositoryService()
					 .createProcessDefinitionQuery()
					 .orderByProcessDefinitionKey().asc() 
					 .list() ;
		/**
		 * 2、过滤出最新版本的流程定义对象
		 * Map<String, ProcessDefinition> 
		 * 		key：流程定义的key
		 * 		value：流程定义的对象
		 * Map集合的特点：当map集合的key相同的情况下，后一次的值将替换前一次的值
		 */
		Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>() ;
		if(list != null && list.size() > 0) {
			for (ProcessDefinition pd : list) {
				map.put(pd.getKey(), pd) ;
			}
		}
		//3、获取最新版本的流程定义对象集合
		List<ProcessDefinition> pdList = new ArrayList<ProcessDefinition>(map.values()) ;
		//4、遍历集合，查看结果
		if(pdList != null && pdList.size() > 0) {
			for (ProcessDefinition pd : pdList) {
				System.out.println("流程定义ID:" + pd.getDeploymentId()); //流程定义的key+版本+随机生成数
				System.out.println("流程定义名称:" + pd.getName()); //对应helloworld.bpmn文件中的name属性值
				System.out.println("流程定义的key:" + pd.getKey()); //对应helloworld.bpmn文件中的id属性值
				System.out.println("流程定义的版本号:" + pd.getVersion()); //当key相同时，版本升级，默认为1
				System.out.println("资源名称bpmn文件:" + pd.getResourceName());
				System.out.println("资源名称png文件:" + pd.getDiagramResourceName());
				System.out.println("部署对象ID:" + pd.getDeploymentId());
				System.out.println("######################################");
			}
		}
	}
	
	/**  
	* @Name: deleteProcessDefinitionByKey（方法的名称）
	* @Description: 附加功能：删除流程定义（删除key相同的所有不同版本的流程定义）（方法的描述）
	* @Author: 李超（作者）
	* @Version: V1.00 （版本号）
	* @Create Date: 2016-12-11 （创建日期）
	* @Parameters: 无（方法的入参，如果没有，填写为“无”）
	* @Return: 无（返回值，如果没有，填写为“无”）
	*/
	@Test
	public void deleteProcessDefinitionByKey() {
		//流程定义的key
		String processDefinitionKey = "helloworld" ;
		//根据流程定义的key查询流程定义，查询出所有的版本
		List<ProcessDefinition> list = processEngine.getRepositoryService()
					 .createProcessDefinitionQuery()
					 .processDefinitionKey(processDefinitionKey) //使用流程定义的key进行查询
					 .list() ;
		//遍历删除
		if(list != null && list.size() > 0) {
			for (ProcessDefinition pd : list) {
				//获取部署id
				String deploymentId = pd.getDeploymentId() ;
				//根据部署id删除流程定义
				processEngine.getRepositoryService().deleteDeployment(deploymentId, true) ;
			}
		}
		System.out.println("删除成功");
	}

}
